<template>
  <div class="smart-input-container" ref="containerRef">
    <div
      ref="editorRef"
      class="smart-input"
      contenteditable="true"
      @input="handleInput"
      @keydown="handleKeydown"
      @click="handleClick"
      @blur="handleBlur"
      @focus="handleFocus"
      :placeholder="placeholder"
      role="textbox"
      aria-multiline="true"
    @paste="handlePaste"
    ></div>
    <div
      v-if="showDropdown && suggestions.length > 0"
      class="suggestions-dropdown"
      :style="dropdownStyle"
    >
      <div
        v-for="(suggestion, index) in suggestions"
        :key="suggestion.key || index"
        class="suggestion-item"
        :class="{ active: index === activeSuggestionIndex }"
        @click="selectSuggestion(suggestion)"
        @mouseenter="activeSuggestionIndex = index"
      >
        {{ suggestion.label || suggestion.key || suggestion }}
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref, onMounted, nextTick, onUnmounted } from 'vue';

// Props
const props = defineProps({
  modelValue: {
    type: String,
    default: ''
  },
  placeholder: {
    type: String,
    default: '输入内容...'
  },
  options: {
    type: Array,
    default: () => [
      { key: 'user', label: 'User' },
      { key: 'date', label: 'Date' },
      { key: 'time', label: 'Time' },
      { key: 'name', label: 'Name' },
      { key: 'email', label: 'Email' },
      { key: 'phone', label: 'Phone' },
      { key: 'address', label: 'Address' },
      { key: 'company', label: 'Company' },
      { key: 'title', label: 'Title' },
      { key: 'description', label: 'Description' }
    ]
  }
});

// Emits
const emit = defineEmits(['update:modelValue', 'change']);

// Refs
const editorRef = ref(null);
const containerRef = ref(null);
const showDropdown = ref(false);
const suggestions = ref([]);
const activeSuggestionIndex = ref(0);
const dropdownStyle = ref({ top: '0px', left: '0px' });
const lastTriggerPosition = ref(-1);

// 获取光标位置
const getCursorPosition = () => {
  const selection = window.getSelection();
  if (!selection.rangeCount) return 0;
  
  const range = selection.getRangeAt(0);
  const preCaretRange = range.cloneRange();
  preCaretRange.selectNodeContents(editorRef.value);
  preCaretRange.setEnd(range.endContainer, range.endOffset);
  
  // 计算文本长度
  let charCount = preCaretRange.toString().length;
  
  // 如果光标在元素节点后，需要特殊处理
  if (range.endContainer.nodeType === Node.ELEMENT_NODE) {
    // 遍历DOM节点计算字符数
    charCount = 0;
    const walker = document.createTreeWalker(
      editorRef.value,
      NodeFilter.SHOW_TEXT,
      null,
      false
    );
    
    let node;
    let lastNodeLength = 0;
    
    while (node = walker.nextNode()) {
      if (node === range.endContainer && range.endOffset === 0) {
        break;
      }
      if (node === range.endContainer) {
        charCount += range.endOffset;
        break;
      }
      charCount += node.nodeValue.length;
      lastNodeLength = node.nodeValue.length;
    }
  }
  
  return charCount;
};

// 设置光标位置
const setCursorPosition = (position) => {
  const textNodes = getTextNodes(editorRef.value);
  let charCount = 0;
  
  for (let i = 0; i < textNodes.length; i++) {
    const node = textNodes[i];
    if (charCount + node.nodeValue.length >= position) {
      const range = document.createRange();
      range.setStart(node, position - charCount);
      range.collapse(true);
      
      const selection = window.getSelection();
      selection.removeAllRanges();
      selection.addRange(range);
      break;
    }
    charCount += node.nodeValue.length;
  }
};

// 获取所有文本节点
const getTextNodes = (node) => {
  const textNodes = [];
  const walker = document.createTreeWalker(
    node,
    NodeFilter.SHOW_TEXT,
    null,
    false
  );
  
  let textNode;
  while (textNode = walker.nextNode()) {
    textNodes.push(textNode);
  }
  return textNodes;
};

// 获取编辑器内容
const getContent = () => {
  return editorRef.value.innerText;
};

// 设置编辑器内容
const setContent = (content) => {
  editorRef.value.innerHTML = content.replace(/\n/g, '<br>');
};

// 检查是否在{}之间
const checkForBraces = (position) => {
  const content = getContent();
  if (position < 2) return false;
  
  // 检查当前位置前的字符
  if (position >= 2 && content[position - 2] === '{' && content[position - 1] === '') {
    return true;
  }
  
  // 更精确的检查：查找最近的未匹配的{
  let openBracePos = -1;
  for (let i = position - 1; i >= 0; i--) {
    if (content[i] === '}') break; // 遇到}则停止查找
    if (content[i] === '{') {
      openBracePos = i;
      break;
    }
  }
  
  if (openBracePos !== -1 && 
      (position === openBracePos + 1 || 
       (position === openBracePos + 2 && content.substring(openBracePos, position).includes('')))) {
    return true;
  }
  
  return false;
};

// 显示下拉框
const showSuggestionDropdown = () => {
  // 获取光标位置
  const position = getCursorPosition();
  lastTriggerPosition.value = position;
  
  // 计算下拉框位置（相对于容器）
  const selection = window.getSelection();
  if (!selection || selection.rangeCount === 0) {
    hideSuggestionDropdown();
    return;
  }
  const range = selection.getRangeAt(0);
  const rect = range.getBoundingClientRect();
  const containerRect = containerRef.value?.getBoundingClientRect();
  if (!containerRect) {
    hideSuggestionDropdown();
    return;
  }

  const offset = 5; // 向下偏移一点
  dropdownStyle.value = {
    top: `${rect.bottom - containerRect.top + offset}px`,
    left: `${rect.left - containerRect.left}px`
  };
  
  // 过滤关键词（以 options 的 key/label 为准）
  const content = getContent();
  const beforeCursor = content.substring(0, position);
  const lastWord = beforeCursor.split(/[^a-zA-Z0-9\u4e00-\u9fa5]/).pop().toLowerCase();

  const normalized = props.options.map((opt) => {
    if (typeof opt === 'string') {
      return { key: opt, label: opt };
    }
    return { key: opt.key, label: opt.label ?? opt.key };
  });

  suggestions.value = normalized.filter(item => 
    item.key.toLowerCase().includes(lastWord) || item.label.toLowerCase().includes(lastWord)
  ).slice(0, 10); // 限制显示10个
  
  showDropdown.value = suggestions.value.length > 0;
  activeSuggestionIndex.value = 0;
};

// 隐藏下拉框
const hideSuggestionDropdown = () => {
  showDropdown.value = false;
  suggestions.value = [];
  activeSuggestionIndex.value = 0;
};

// 插入关键词
const insertKeyword = (keywordOrItem) => {
  const key = typeof keywordOrItem === 'string' ? keywordOrItem : (keywordOrItem?.key ?? '');
  const content = getContent();
  const cursorPos = getCursorPosition();
  
  // 找到最近的{
  let openBracePos = -1;
  for (let i = cursorPos - 1; i >= 0; i--) {
    if (content[i] === '}') break;
    if (content[i] === '{') {
      openBracePos = i;
      break;
    }
  }
  
  if (openBracePos !== -1) {
    const targetReplaceStr = `{${key}}`
    // 替换{}之间的内容
    const newContent = content.substring(0, openBracePos + 1) + targetReplaceStr + content.substring(cursorPos);
    setContent(newContent);
    
    // 设置光标到关键词后
    setCursorPosition(openBracePos + key.length + 2);
    
    // 触发更新事件
    emit('update:modelValue', newContent);
    emit('change', newContent);
  }
  
  hideSuggestionDropdown();
};

// 插入花括号对
const insertBraces = () => {
  const content = getContent();
  const cursorPos = getCursorPosition();
  
  // 在光标位置插入{}
  const newContent = content.slice(0, cursorPos) + '{}' + content.slice(cursorPos);
  setContent(newContent);
  
  // 将光标移动到{和}之间
  setCursorPosition(cursorPos + 1);
  
  // 触发更新事件
  emit('update:modelValue', newContent);
  emit('change', newContent);
  
  // 等待DOM更新后显示下拉建议
  nextTick(() => {
    showSuggestionDropdown();
  });
};

// 处理输入事件
const handleInput = (event) => {
  const content = getContent();
  emit('update:modelValue', content);
  emit('change', content);
  
  // 检查是否需要显示下拉框
  const cursorPos = getCursorPosition();
  
  // 检查是否刚输入了{
  if (event.inputType === 'insertText' && event.data === '{') {
    // 等待DOM更新后再设置光标
    nextTick(() => {
      setCursorPosition(cursorPos);
      showSuggestionDropdown();
    });
  } 
  // 检查是否在{}之间输入了字符
  else if (checkForBraces(cursorPos)) {
    showSuggestionDropdown();
  } 
  // 如果输入了其他字符，隐藏下拉框
  else {
    hideSuggestionDropdown();
  }
};

// 处理键盘事件
const handleKeydown = (event) => {
  // 禁止换行（Enter 和 Shift+Enter），当需要选择下拉时也不允许插入换行
  if (event.key === 'Enter') {
    event.preventDefault();
    // 若下拉可见，回车作为选择
    if (showDropdown.value && suggestions.value[activeSuggestionIndex.value]) {
      selectSuggestion(suggestions.value[activeSuggestionIndex.value]);
    }
    return;
  }

  // 检测 Shift+{ 快捷键
  if (event.shiftKey && event.key === '{' && !event.ctrlKey && !event.altKey && !event.metaKey) {
    
    event.preventDefault(); // 阻止默认行为
    insertBraces();
    return;
  }
  
  if (showDropdown.value) {
    switch (event.key) {
      case 'ArrowDown':
        event.preventDefault();
        activeSuggestionIndex.value = (activeSuggestionIndex.value + 1) % suggestions.value.length;
        break;
        
      case 'ArrowUp':
        event.preventDefault();
        activeSuggestionIndex.value = activeSuggestionIndex.value === 0 
          ? suggestions.value.length - 1 
          : activeSuggestionIndex.value - 1;
        break;
        
      case 'Enter':
        event.preventDefault();
        if (suggestions.value[activeSuggestionIndex.value]) {
          selectSuggestion(suggestions.value[activeSuggestionIndex.value]);
        }
        break;
        
      case 'Escape':
        event.preventDefault();
        hideSuggestionDropdown();
        break;
        
      case 'Tab':
        event.preventDefault();
        if (suggestions.value[activeSuggestionIndex.value]) {
          selectSuggestion(suggestions.value[activeSuggestionIndex.value]);
        }
        break;
    }
  }
  // 如果按了}，并且在{之后，自动跳到下拉框选择
  else if (event.key === '}') {
    const cursorPos = getCursorPosition();
    const content = getContent();
    if (cursorPos > 0 && content[cursorPos - 1] === '{') {
      showSuggestionDropdown();
    }
  }
};

// 处理点击事件
const handleClick = () => {
  if (showDropdown.value) {
    hideSuggestionDropdown();
  }
};

// 处理粘贴：移除换行符
const handlePaste = (event) => {
  event.preventDefault();
  const clipboardData = event.clipboardData || window.clipboardData;
  let text = clipboardData ? clipboardData.getData('text') : '';
  text = text.replace(/[\r\n]+/g, ' ');

  // 使用 execCommand 插入到 contenteditable
  document.execCommand('insertText', false, text);
};

// 处理失焦事件
const handleBlur = () => {
  // 延迟隐藏，以便点击下拉项时不会立即消失
  setTimeout(hideSuggestionDropdown, 150);
};

// 处理聚焦事件
const handleFocus = () => {
  // 聚焦时不需要特殊处理
};

// 选择下拉项
const selectSuggestion = (suggestion) => {
  insertKeyword(suggestion);
};

// 初始化内容
onMounted(() => {
  if (props.modelValue) {
    setContent(props.modelValue);
  }
  
  // 添加全局点击事件监听器来隐藏下拉框
  const handleClickOutside = (event) => {
    if (editorRef.value && !editorRef.value.contains(event.target) &&
        (!document.querySelector('.suggestions-dropdown') || 
         !document.querySelector('.suggestions-dropdown').contains(event.target))) {
      hideSuggestionDropdown();
    }
  };
  
  document.addEventListener('click', handleClickOutside);
  
  // 组件卸载时移除事件监听器
  onUnmounted(() => {
    document.removeEventListener('click', handleClickOutside);
  });
});
</script>

<style scoped>
.smart-input-container {
  position: relative;
  width: 100%;
  font-family: inherit;
}

.smart-input {
  min-height: 100px;
  width: 100%;
  padding: 12px;
  border: 1px solid #d1d5db;
  border-radius: 6px;
  outline: none;
  font-size: 14px;
  line-height: 1.5;
  box-sizing: border-box;
  background-color: white;
  box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
  overflow-wrap: break-word;
  word-wrap: break-word;
  white-space: pre-wrap;
}

.smart-input:focus {
  border-color: #3b82f6;
  box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
}

.smart-input:empty:before {
  content: attr(placeholder);
  color: #9ca3af;
  pointer-events: none;
}

.suggestions-dropdown {
  position: absolute;
  z-index: 1000;
  background: white;
  border: 1px solid #d1d5db;
  border-radius: 6px;
  box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
  max-height: 200px;
  overflow-y: auto;
  min-width: 200px;
}

.suggestion-item {
  padding: 8px 12px;
  cursor: pointer;
  font-size: 14px;
  color: #1f2937;
  transition: background-color 0.2s;
}

.suggestion-item:hover,
.suggestion-item.active {
  background-color: #3b82f6;
  color: white;
}

.suggestion-item:not(:last-child) {
  border-bottom: 1px solid #e5e7eb;
}
</style>



